trait HasArea {
    fn area(&self) -> f64;
}

struct Circle{
    x: f64,
    y: f64,
    radius: f64,
}

impl HasArea for Circle {
    fn area(&self) -> f64 {
        PI * (self.radius * self.radius)
    }
}

struct Square {
    x: f64,
    y: f64,
    side: f64,
}

impl HasArea for Square {
    fn area(&self) -> f64 {
        self.side * self.side
    }
}
//函数print_area()中的泛型参数T被添加了一个名为HasArea的特性约束 (trait constraint)，
// 用以确保任何实现了HasArea的类型将拥有一个.area()方法。 如果需要多个特性限定 (multiple trait bounds)，可以使用+：
fn print_area<T: HasArea>(shape: T) {
    println!("This shape has an area of {}", shape.area());
}

fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
    x.clone();
    y.clone();
    println!("{:?}", y);
}
fn bar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug {
    x.clone();
    y.clone();
    println!("{:?}", y);
}

//定义在特性中的方法称为默认方法 (default method)，可以被该特性的实现覆盖。 此外，特性之间也可以存在继承 (inheritance)：
trait Foo {
    fn foo(&self);
    // default method
    fn bar(&self){
        println!("we called bar.");
    }
}
//继承
trait FooBar: Foo {
    fn foobar(&self);
}
struct Baz;
impl Foo for Baz {
    fn foo(&self) {
        println!("foo");
    }
}
impl FooBar for Baz {
    fn foobar(&self) {
        println!("foobar");
    }
}